/* Filename: snder.c
 * Description: 报式socket组播
 * nohup ./snder 239.255.255.249 enp1s0 2>&1 &
 * Last modified: humble 2020-06-15 23:45
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <net/if.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include "proto.h"

#define IPSTRSIZE (40)

static void usage(char *argv0);

int main(int argc, char **argv)
{
    int sd;
    struct sockaddr_in /*laddr,*/raddr;
    //struct msg_st sbuf;
    char sbuf[256] = {0};
    socklen_t raddr_len;
    char ipstr[IPSTRSIZE];

    if(argc != 3){ fprintf(stderr, "argc !=3\n"); usage(argv[0]); exit(1); }

    sd = socket(AF_INET, SOCK_DGRAM, 0/*IPPROTO_UDP*/);
    if(sd < 0){ perror("socket()"); exit(1); }

    struct ip_mreqn mreq;
    //inet_pton(AF_INET, MGROUP, &mreq.imr_multiaddr);
    inet_pton(AF_INET, argv[1], &mreq.imr_multiaddr);
    inet_pton(AF_INET, "0.0.0.0" , &mreq.imr_address);
    mreq.imr_ifindex = if_nametoindex(argv[2]); //网卡索引号

    if(setsockopt(sd, IPPROTO_IP, IP_MULTICAST_IF, &mreq, sizeof(mreq)) < 0){
        perror("setsockopt(IP_ADD_MEMBERSHIP,if_name)");
        exit(1);
    }

    int ttl = 15; //如果不设置，默认为1（奇怪）
    if(setsockopt(sd, IPPROTO_IP, IP_MULTICAST_TTL, (char *)&ttl, sizeof(ttl)) < 0){
        perror("setsockopt(ttl)");
        exit(1);
    }

    /* 发送方可省略bind */
    /*
    laddr.sin_family = AF_INET;
    laddr.sin_port = htons(atoi(RCVPORT));
    inet_pton(AF_INET, "0.0.0.0", &laddr.sin_addr);

    if(bind(sd, (void *)&laddr, sizeof(laddr)) < 0){
        perror("bind()");
        exit(1);
    }
    */

    int count = 36000; //10hour
    while(count--){
        //memset(&sbuf, 0, sizeof(sbuf));
        //sprintf((char *)sbuf.name, "Alan%d", count);
        //sbuf.math = htonl(rand() % 100);
        //sbuf.chinese = htonl(rand() % 100);
        memset(sbuf, 0, sizeof(sbuf));
        sprintf(sbuf, "i am the %dth message to %s", count, argv[1]);

        raddr.sin_family = AF_INET;
        raddr.sin_port = htons(atoi(RCVPORT));
        //inet_pton(AF_INET, MGROUP, &raddr.sin_addr); //所有支持多播的节点默认都在组播224.0.0.1内并且无法取消,往该地址发相当于广播
        inet_pton(AF_INET, argv[1], &raddr.sin_addr);

        //发送放的sendto函数不用回填raddr_len
        /* 重要：若没初始化该值，则会导致第一次收到数据出错 */
        //raddr_len = sizeof(raddr);

        //if(sendto(sd, &sbuf, sizeof(sbuf), 0, (void *)&raddr, sizeof(raddr)) < 0){
        if(sendto(sd, sbuf, sizeof(sbuf), 0, (void *)&raddr, sizeof(raddr)) < 0){
            perror("sendto()");
            exit(1);
        }
        sleep(7);
    }

    puts("ok!");

    close(sd);
    return 0;
}

static void usage(char *argv0)
{
#define USAGE "Usage:\n\
  %s <ipaddr> <if_name>\n"
    printf(USAGE, argv0);
}
